package 实现简单的依赖注入;

import java.lang.annotation.Retention;
import java.lang.reflect.Field;

interface MessageService {
    void sendMessage(String message);
}

class EmailService implements MessageService {
    @Override
    public void sendMessage(String message) {
        System.out.println("Sending email: " + message);
    }
}

class SMSService implements MessageService {
    @Override
    public void sendMessage(String message) {
        System.out.println("Sending SMS: " + message);
    }
}

class NotificationService {
    @AutoInject
    private MessageService messageService;
    
    public void sendNotification(String message) {
        messageService.sendMessage(message);
    }
}

public class SimpleDependencyInjection {
    public static void main(String[] args) throws Exception {
        // 创建服务实例
        NotificationService notificationService = new NotificationService();
        
        // 注入依赖
        injectDependencies(notificationService);
        
        // 使用服务
        notificationService.sendNotification("Hello World!");
    }
    
    private static void injectDependencies(Object target) throws Exception {
        Class<?> clazz = target.getClass();
        
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(AutoInject.class)) {
                field.setAccessible(true);
                
                // 根据接口类型创建实现类实例
                Object implementation = createImplementation(field.getType());
                if (implementation != null) {
                    field.set(target, implementation);
                }
            }
        }
    }
    
    private static Object createImplementation(Class<?> interfaceType) throws Exception {
        // 这里简单根据接口类型返回固定实现，实际中可以更灵活
        if (interfaceType == MessageService.class) {
            return new EmailService(); // 可以改为SMSService测试不同实现
        }
        return null;
    }
}

// 自定义注解


/*
Java 的注解默认是 RetentionPolicy.CLASS，也就是说：
注解只在 .class 文件中存在
运行时（Runtime）不可见
而你在代码中使用的是反射（Reflection），是在运行时读取注解信息的。如果注解没有标记为 @Retention(RetentionPolicy.RUNTIME)，那么运行时就无法通过反射访问到它！
* */
//添加 @Retention(RUNTIME)
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@interface AutoInject {
    //Class messageService();
}